/*
 *
 * Saturn Framework Co.Limt
 * Copyright (c) 2012-2019 tanks, Inc. All rights reserved.
 */
 
package com.saturn.config.server.service.impl;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import org.apache.commons.lang3.StringUtils;
import org.jasypt.encryption.StringEncryptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.saturn.config.server.base.dto.ConfigInfo;
import com.saturn.config.server.base.entity.AppConfig;
import com.saturn.config.server.base.entity.AppInfo;
import com.saturn.config.server.base.entity.ConfigLog;
import com.saturn.config.server.base.entity.SysUser;
import com.saturn.config.server.base.mapper.AppConfigMapper;
import com.saturn.config.server.base.mapper.AppInfoMapper;
import com.saturn.config.server.base.mapper.ConfigLogMapper;
import com.saturn.config.server.service.AppConfigService;

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;

/**
 * <dl>
 *    <dt><b>Title:</b></dt>
 *    <dd>
 *    	none
 *    </dd>
 *    <dt><b>Description:</b></dt>
 *    <dd>
 *    	<p>应用配置项
 *    </dd>
 *
 * @author tanks
 * @date 2019-07-08 15:58:43
 */
@Slf4j
@Service
public class AppConfigServiceImpl extends ServiceImpl<AppConfigMapper, AppConfig> implements AppConfigService {

	@Autowired
	private ConfigLogMapper configLogMapper;
	@Autowired
	private AppInfoMapper appInfoMapper;
	@Autowired
	private StringEncryptor stringEncryptor;
	
	
	public IPage<ConfigInfo> queryPage(IPage<ConfigInfo> page, Map<String,Object> params){
		return this.baseMapper.queryPage(page, params);
	}

	@Override
	@Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW)
	public boolean saveAdd(AppConfig appConfig) {
		AppInfo appInfo = appInfoMapper.selectById(appConfig.getAppId());
		QueryWrapper queryWrapper = Wrappers.query();
		queryWrapper.eq("app_id", appConfig.getAppId());
		queryWrapper.eq("config_key", appConfig.getConfigKey());
		queryWrapper.eq("version", appInfo.getCurrentVersion());
		int count = count(queryWrapper);
		if( count>0 ) {
			log.info("应用中已经存在此配置项，无法覆盖，保存失败！");
			return false;
		}
		//检查是否需要加密
		if( StringUtils.isBlank(appConfig.getIsEncrypt()) ) {
			appConfig.setIsEncrypt("0");
		}
		if( "true".equals(appConfig.getIsEncrypt()) || "on".equals(appConfig.getIsEncrypt()) ) {
			appConfig.setIsEncrypt("1");
		}
		if("1".equals(appConfig.getIsEncrypt()) ) {
			appConfig.setConfigValue(stringEncryptor.encrypt(appConfig.getConfigValue()));
		}
		appConfig.setVersion(appInfo.getCurrentVersion());
		boolean success = save(appConfig);
		//保存日志
		ConfigLog configLog = new ConfigLog();
		configLog.setAppId(appConfig.getAppId());
		configLog.setConfigId(appConfig.getConfigId());
		configLog.setCreateTime(LocalDateTime.now());
		configLog.setIsCast("0");
		configLog.setIsPublic("0");
		configLog.setNewJson(JSONUtil.toJsonStr(appConfig));
		configLog.setOperateType("0");
		configLogMapper.insert(configLog);
		return success;
	}

	@Override
	@Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW)
	public int deleteRecords(String[] configIds) {
		//批量删除数据
		List<String> idList = new ArrayList<String>();
		for(String id:configIds){
			idList.add(id);
		}
		List<AppConfig> appConfigs = this.getBaseMapper().selectBatchIds(idList);
		int count = this.getBaseMapper().deleteBatchIds(idList);
		log.info("共删除配置项记录总数：" + count);
		//批量删除新增、修改的未广播记录
		count = configLogMapper.deleteBatchByConfigIds(idList, "0");
		log.info("共删除新增未广播总数：" + count);
		//插入新增删除的广播记录
		for(AppConfig appConfig:appConfigs) {
			//保存日志
			ConfigLog configLog = new ConfigLog();
			configLog.setAppId(appConfig.getAppId());
			configLog.setConfigId(appConfig.getConfigId());
			configLog.setCreateTime(LocalDateTime.now());
			configLog.setIsCast("0");
			configLog.setIsPublic("0");
			configLog.setNewJson(JSONUtil.toJsonStr(appConfig));
			configLog.setOperateType("2");
			configLogMapper.insert(configLog);
		}
		log.info("共新增广播删除配置项记录总数：" + appConfigs.size());
		count = appConfigs.size();
		return count;
	}
	
	/**
	 * 批量保存数据
	 * @param appConfigs
	 * @return
	 * @throws Exception
	 */
	@Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW)
	public int batchSaveConfigRecord(List<AppConfig> appConfigs) throws Exception {
		if( appConfigs==null || appConfigs.size()==0 ) return 0;
		int updateCount = 0;
		for(AppConfig appConfig:appConfigs ){
			appConfig.setUpdateTime(LocalDateTime.now());
			QueryWrapper queryWrapper = Wrappers.query();
			queryWrapper.eq("app_id", appConfig.getAppId());
			queryWrapper.eq("config_key", appConfig.getConfigKey());
			queryWrapper.eq("version", appConfig.getVersion());
			AppConfig entity = this.baseMapper.selectOne(queryWrapper);
			if( entity!=null && entity.getConfigId().longValue()!=appConfig.getConfigId().longValue()) {
				log.info("AppId:" + appConfig.getAppId() + ",ConfigKey:" + appConfig.getConfigKey() + ",变更数据与原有数据重复，无法修改");
				throw new Exception("变更数据与原有数据重复，无法修改");
			}
			entity = this.baseMapper.selectById(appConfig.getConfigId());
			if( "1".equals(appConfig.getIsEncrypt()) && "0".equals(entity.getIsEncrypt())) {
				//加密
				appConfig.setConfigValue("{cipher}" + stringEncryptor.encrypt(appConfig.getConfigValue()));
			}else if( "0".equals(appConfig.getIsEncrypt()) && "1".equals(appConfig.getIsEncrypt())) {
				//解密
				if( appConfig.getConfigValue().equals(entity.getConfigValue()) ) {
					appConfig.setConfigValue(stringEncryptor.decrypt(appConfig.getConfigValue().replace("{cipher}", StrUtil.EMPTY)));
				}
			}else if( "1".equals(appConfig.getIsEncrypt()) && "1".equals(entity.getIsEncrypt())) {
				//都加密的情况，看内容是否变化
				if( !appConfig.getConfigValue().equals(entity.getConfigValue()) ) {
					appConfig.setConfigValue("{cipher}" + stringEncryptor.encrypt(appConfig.getConfigValue()));
				}
			}
			int count = this.baseMapper.updateById(appConfig);
			queryWrapper = Wrappers.query();
			queryWrapper.eq("app_id", appConfig.getAppId());
			queryWrapper.eq("config_id",appConfig.getConfigId());
			queryWrapper.in("operate_type", new String[]{"0","1"});
			queryWrapper.eq("is_cast", "0");
			ConfigLog configLog = configLogMapper.selectOne(queryWrapper);
			if( configLog!=null ) {
				configLog.setUpdateTime(LocalDateTime.now());
				//变成修改状态
				configLog.setOriginJson(JSONUtil.toJsonStr(entity));
				configLog.setNewJson(JSONUtil.toJsonStr(appConfig));
				configLogMapper.updateById(configLog);
			}else {
				configLog = new ConfigLog();
				configLog.setAppId(appConfig.getAppId());
				configLog.setConfigId(appConfig.getConfigId());
				configLog.setCreateTime(LocalDateTime.now());
				configLog.setIsCast("0");
				configLog.setIsPublic("0");
				configLog.setOriginJson(JSONUtil.toJsonStr(entity));
				configLog.setNewJson(JSONUtil.toJsonStr(appConfig));
				configLog.setOperateType("1");
				configLogMapper.insert(configLog);
			}
			updateCount += count;
		}
		return updateCount;
	}
	
	/**
	 * 上传配置
	 */
	@Override
	@Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW)
	public int uploadProperties(SysUser sysUser,Properties props,boolean overProp,String appId){
		AppInfo appInfo = appInfoMapper.selectById(appId);
		if( appInfo==null ) {
			log.info(appId + " 应用已经被删除或不存在，无法新增记录！");
			return 0;
		}
		QueryWrapper queryWrapper = Wrappers.query();
		queryWrapper.eq("app_id", appId);
		List<AppConfig> configs = this.baseMapper.selectList(queryWrapper);
		Map<String,AppConfig> configMap = listToMap(configs);
		Enumeration<Object> e = props.keys();
		int effect = 0;
		while (e.hasMoreElements()) {
			String configkey = ((String)e.nextElement()).trim();
			if(configMap.containsKey(configkey)){
				if(overProp){
					AppConfig configExists = configMap.get(configkey);
					String oriExistsJson = JSONObject.toJSON(configExists).toString();
					configExists.setConfigValue(props.getProperty(configkey));
					configExists.setMemo(configExists.getMemo()+"上传修改");
					configExists.setUpdateTime(LocalDateTime.now());
					configExists.setUserId(sysUser.getId());
					int u = this.getBaseMapper().updateById(configExists);
					String newjson = JSONObject.toJSON(configExists).toString();
					//查询原来未广播新增的ID是否存在，存在则直接更新该记录
					queryWrapper = Wrappers.query();
					queryWrapper.eq("app_id", appId);
					queryWrapper.eq("config_id",configExists.getConfigId());
					queryWrapper.in("operate_type", new String[]{"0","1"});
					queryWrapper.eq("is_cast", "0");
					ConfigLog configLog = configLogMapper.selectOne(queryWrapper);
					if( configLog!=null ) {
						configLog.setUpdateTime(LocalDateTime.now());
						//变成修改状态
						configLog.setOriginJson(oriExistsJson);
						configLog.setNewJson(newjson);
						configLogMapper.updateById(configLog);
					}else {
						configLog = new ConfigLog();
						configLog.setAppId(configExists.getAppId());
						configLog.setConfigId(configExists.getConfigId());
						configLog.setCreateTime(LocalDateTime.now());
						configLog.setIsCast("0");
						configLog.setIsPublic("0");
						configLog.setOriginJson(oriExistsJson);
						configLog.setNewJson(newjson);
						configLog.setOperateType("1");
						configLogMapper.insert(configLog);
					}
					effect += u;
				}
				continue;
			}
			//新增配置项			
			AppConfig appConfig = new AppConfig();
			appConfig.setAppId(Long.parseLong(appId));
			appConfig.setConfigKey(configkey);
			appConfig.setConfigValue((props.getProperty(configkey)).trim());
			appConfig.setCreateTime(LocalDateTime.now());
			appConfig.setType("S");
			appConfig.setIsEncrypt("0");
			appConfig.setMemo("上传添加");
			appConfig.setUserId(sysUser.getId());
			appConfig.setVersion(appInfo.getCurrentVersion());
			int t = this.baseMapper.insert(appConfig);
			ConfigLog configLog = new ConfigLog();
			configLog.setAppId(appConfig.getAppId());
			configLog.setConfigId(appConfig.getConfigId());
			configLog.setCreateTime(LocalDateTime.now());
			configLog.setIsCast("0");
			configLog.setIsPublic("0");
			configLog.setNewJson(JSONUtil.toJsonStr(appConfig));
			configLog.setOperateType("0");
			configLogMapper.insert(configLog);
			effect += t;
		}
		return effect;
	}
	
	/**
	 * 
	 * @param configs
	 * @return
	 */
	private Map<String,AppConfig> listToMap(List<AppConfig> configs){
		Map<String,AppConfig> configMap = new HashMap<String, AppConfig>();
		for (AppConfig config : configs) {
			configMap.put(config.getConfigKey(), config);
		}
		return configMap;
	}

	@Override
	public List<ConfigInfo> queryAppConfigs(Map<String, Object> params) {
		//查询公共配置信息
		QueryWrapper<AppInfo> queryWrapper = Wrappers.query();
		queryWrapper.eq("app_name", params.get("appName"));
		queryWrapper.eq("env_type", params.get("envType"));
		queryWrapper.eq("current_version", params.get("version"));
		AppInfo appInfo = this.appInfoMapper.selectOne(queryWrapper);
		List<ConfigInfo> appConfigs = this.baseMapper.queryAppConfigs(params);
		boolean include = Boolean.FALSE.booleanValue();
		if( appInfo==null || (appInfo!=null && "1".equals(appInfo.getIncludePublic()))){
			include = Boolean.TRUE.booleanValue();
		}
		if( include ) {
			List<ConfigInfo> publicConfigs = this.baseMapper.queryAppPublicConfigs(params);
			publicConfigs.addAll(appConfigs);
			return publicConfigs;
		}else {
			return appConfigs;
		}
	}

}
